import pandas as pd


class MetricCalculator:
    """指标计算器，负责所有业务指标的计算"""

    def __init__(self, data_accessor):
        self.data_accessor = data_accessor
        self.time_periods = data_accessor.get_time_periods()

    def calculate_lead_reinsurer_contract_ratio(self, period, region_id=None):
        """
        1. 计算首席再保人合同数量占比
        计算公式：首席再保人合同数量 ÷ 合同总量 × 100%
        """
        # 筛选再保财险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type="再保财险"
        )

        if len(filtered) == 0:
            return 0

        lead_count = filtered[filtered["is_lead_reinsurer"] == True].shape[0]
        total_count = filtered.shape[0]

        return (lead_count / total_count) * 100

    def calculate_lead_reinsurer_premium_ratio(self, period, region_id=None):
        """
        2. 计算首席再保人保费收入占比
        计算公式：首席再保人的分保费收入 ÷ 分保费收入 × 100%
        """
        # 筛选再保财险和再保人身险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["再保财险", "再保人身险"]
        )

        if len(filtered) == 0:
            return 0

        lead_premium = filtered[filtered["is_lead_reinsurer"] == True]["reinsurance_premium"].sum()
        total_premium = filtered["reinsurance_premium"].sum()

        if total_premium == 0:
            return 0

        return (lead_premium / total_premium) * 100

    def calculate_term_premium_growth_rate(self, period, insurance_type, region_id=None):
        """
        3. 计算长/短期险保费增长率
        计算公式：(报告期保费 - 基期保费) ÷ 基期保费 × 100%
        """
        # 获取基期（上一季度）
        period_year = int(period[:4])
        period_quarter = int(period[5:])

        if period_quarter == 1:
            base_period = f"{period_year - 1}Q4"
        else:
            base_period = f"{period_year}Q{period_quarter - 1}"

        # 如果基期不存在，返回0
        if base_period not in self.time_periods:
            return 0

        # 筛选人身险和再保人身险业务
        current_filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )
        current_filtered = current_filtered[current_filtered["insurance_type"] == insurance_type]

        base_filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=base_period,
            business_type=["人身险", "再保人身险"]
        )
        base_filtered = base_filtered[base_filtered["insurance_type"] == insurance_type]

        current_premium = current_filtered["premium_income"].sum()
        base_premium = base_filtered["premium_income"].sum()

        if base_premium == 0:
            return 0

        return ((current_premium - base_premium) / base_premium) * 100

    def calculate_term_premium_ratio(self, period, insurance_type, region_id=None):
        """
        4. 计算长/短期险保费占比
        计算公式：长/短期险保费 ÷ 总保费 × 100%
        """
        # 筛选人身险和再保人身险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )

        if len(filtered) == 0:
            return 0

        term_premium = filtered[filtered["insurance_type"] == insurance_type]["premium_income"].sum()
        total_premium = filtered["premium_income"].sum()

        if total_premium == 0:
            return 0

        return (term_premium / total_premium) * 100

    def calculate_customer_type_premium_ratio(self, period, customer_type, region_id=None):
        """
        5. 计算团/个险保费占比
        计算公式：团/个险保费 ÷ 总保费 × 100%
        """
        # 筛选人身险和再保人身险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )

        if len(filtered) == 0:
            return 0

        customer_premium = filtered[filtered["customer_type"] == customer_type]["premium_income"].sum()
        total_premium = filtered["premium_income"].sum()

        if total_premium == 0:
            return 0

        return (customer_premium / total_premium) * 100

    def calculate_first_year_premium_ratio(self, period, policy_type, region_id=None):
        """
        6. 计算首年期/趸缴保费占比
        计算公式：新单首年期/趸缴保费 ÷ 新单首年总保费 × 100%
        """
        # 筛选人身险和再保人身险业务，且为有效合同
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )
        filtered = filtered[
            (filtered["status"] == "有效") &
            (filtered["policy_type"].isin(["首年期缴", "趸缴"]))
            ]

        if len(filtered) == 0:
            return 0

        policy_premium = filtered[filtered["policy_type"] == policy_type]["premium_income"].sum()
        total_premium = filtered["premium_income"].sum()

        if total_premium == 0:
            return 0

        return (policy_premium / total_premium) * 100

    def calculate_long_term_payment_ratio(self, period, region_id=None):
        """
        7. 计算10年期及以上期缴保费占比
        计算公式：10年期及以上首年期缴保费 ÷ 首年期缴总保费 × 100%
        """
        # 筛选人身险和再保人身险业务，且为首年期缴
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )
        filtered = filtered[filtered["policy_type"] == "首年期缴"]

        if len(filtered) == 0:
            return 0

        long_term_premium = filtered[filtered["term"] >= 10]["premium_income"].sum()
        total_premium = filtered["premium_income"].sum()

        if total_premium == 0:
            return 0

        return (long_term_premium / total_premium) * 100

    def calculate_free_look_withdrawal_rate(self, period, region_id=None):
        """
        8. 计算犹豫期保费退保率
        计算公式：犹豫期撤单保费 ÷ (新单原保费收入 + 犹豫期撤单保费) × 100%
        """
        # 筛选人身险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type="人身险"
        )

        if len(filtered) == 0:
            return 0

        withdrawal_premium = filtered["free_look_withdrawal"].sum()
        new_premium = filtered[filtered["status"] == "有效"]["premium_income"].sum()

        denominator = new_premium + withdrawal_premium
        if denominator == 0:
            return 0

        return (withdrawal_premium / denominator) * 100

    def calculate_new_business_value_ratio(self, period, region_id=None):
        """
        9. 计算新单业务价值占比
        计算公式：新单业务价值 ÷ 有效业务价值 × 100%
        """
        # 筛选人身险和再保人身险业务，且为有效合同
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["人身险", "再保人身险"]
        )
        filtered = filtered[filtered["status"] == "有效"]

        if len(filtered) == 0:
            return 0

        new_value = filtered["new_business_value"].sum()
        effective_value = filtered["effective_business_value"].sum()

        if effective_value == 0:
            return 0

        return (new_value / effective_value) * 100

    def calculate_asset_increment_ratio(self, period, region_id=None):
        """
        10. 计算资产增量保费比
        计算公式：(期末总资产 - 期初总资产) ÷ 报告期保险业务收入 × 100%
        """
        # 获取资产数据
        asset_data = self.data_accessor.get_assets(region_id=region_id, period=period)

        # 获取同期保费收入
        contracts = self.data_accessor.get_contracts(region_id=region_id, period=period)

        if len(asset_data) == 0 or len(contracts) == 0:
            return 0

        # 计算资产增量
        asset_increment = asset_data["end_asset"].sum() - asset_data["start_asset"].sum()

        # 计算保费收入
        premium_income = contracts["premium_income"].sum()

        if premium_income == 0:
            return 0

        return (asset_increment / premium_income) * 100

    def calculate_premium_estimation_error_ratio(self, period, region_id=None):
        """
        11. 计算保费预估差异率
        计算公式：(预估分保费收入 - 实际分保费收入) ÷ 实际分保费收入 × 100%
        """
        # 筛选再保财险和再保人身险业务
        filtered = self.data_accessor.get_contracts(
            region_id=region_id,
            period=period,
            business_type=["再保财险", "再保人身险"]
        )

        if len(filtered) == 0:
            return 0

        estimated = filtered["estimated_premium"].sum()
        actual = filtered["reinsurance_premium"].sum()

        if actual == 0:
            return 0

        return ((estimated - actual) / actual) * 100

    def calculate_all_metrics(self):
        """计算所有业务指标并返回汇总数据"""
        metrics_data = []
        regions = self.data_accessor.get_regions()

        # 遍历所有时间周期和区域
        for period in self.time_periods:
            for region_id in regions["region_id"].unique():
                # 1. 首席再保人合同数量占比
                metric1 = self.calculate_lead_reinsurer_contract_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "首席再保人合同数量占比",
                    "metric_value": round(metric1, 2),
                    "applicable_business": "再保财险业务",
                    "metric_description": "作为首席再保人的合同数量占合同总量的比重"
                })

                # 2. 首席再保人保费收入占比
                metric2 = self.calculate_lead_reinsurer_premium_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "首席再保人保费收入占比",
                    "metric_value": round(metric2, 2),
                    "applicable_business": "再保财险业务、再保人身险业务",
                    "metric_description": "作为首席再保人的合同的分保费收入占总分保费收入的比重"
                })

                # 3. 长期险保费增长率
                metric3_long = self.calculate_term_premium_growth_rate(period, "长期险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "长期险保费增长率",
                    "metric_value": round(metric3_long, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "报告期长期险保费收入相对于基期的增长率"
                })

                # 3. 短期险保费增长率
                metric3_short = self.calculate_term_premium_growth_rate(period, "短期险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "短期险保费增长率",
                    "metric_value": round(metric3_short, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "报告期短期险保费收入相对于基期的增长率"
                })

                # 4. 长期险保费占比
                metric4_long = self.calculate_term_premium_ratio(period, "长期险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "长期险保费占比",
                    "metric_value": round(metric4_long, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "长期险保费收入占总保费收入的比重"
                })

                # 4. 短期险保费占比
                metric4_short = self.calculate_term_premium_ratio(period, "短期险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "短期险保费占比",
                    "metric_value": round(metric4_short, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "短期险保费收入占总保费收入的比重"
                })

                # 5. 团险保费占比
                metric5_group = self.calculate_customer_type_premium_ratio(period, "团险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "团险保费占比",
                    "metric_value": round(metric5_group, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "团险保费收入占总保费收入的比重"
                })

                # 5. 个险保费占比
                metric5_individual = self.calculate_customer_type_premium_ratio(period, "个险", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "个险保费占比",
                    "metric_value": round(metric5_individual, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "个险保费收入占总保费收入的比重"
                })

                # 6. 首年期缴保费占比
                metric6_first = self.calculate_first_year_premium_ratio(period, "首年期缴", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "首年期缴保费占比",
                    "metric_value": round(metric6_first, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "新单首年期缴保费收入占新单首年总保费收入的比重"
                })

                # 6. 趸缴保费占比
                metric6_lump = self.calculate_first_year_premium_ratio(period, "趸缴", region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "趸缴保费占比",
                    "metric_value": round(metric6_lump, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "新单趸缴保费收入占新单首年总保费收入的比重"
                })

                # 7. 10年期及以上期缴保费占比
                metric7 = self.calculate_long_term_payment_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "10年期及以上期缴保费占比",
                    "metric_value": round(metric7, 2),
                    "applicable_business": "人身险业务、再保人身险业务",
                    "metric_description": "10年期及以上首年期缴保费收入占首年期缴总保费收入的比重"
                })

                # 8. 犹豫期保费退保率
                metric8 = self.calculate_free_look_withdrawal_rate(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "犹豫期保费退保率",
                    "metric_value": round(metric8, 2),
                    "applicable_business": "人身险业务",
                    "metric_description": "报告期犹豫期撤单保费占报告期新单原保费收入与犹豫期撤单保费之和的比重"
                })

                # 9. 新单业务价值占比
                metric9 = self.calculate_new_business_value_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "新单业务价值占比",
                    "metric_value": round(metric9, 2),
                    "applicable_business": "人身险公司、再保人身险业务",
                    "metric_description": "报告期新单的有效业务价值占总有效业务价值的比重"
                })

                # 10. 资产增量保费比
                metric10 = self.calculate_asset_increment_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "资产增量保费比",
                    "metric_value": round(metric10, 2),
                    "applicable_business": "财险业务、人身险业务",
                    "metric_description": "报告期内总资产增量与保险业务收入的比率"
                })

                # 11. 保费预估差异率
                metric11 = self.calculate_premium_estimation_error_ratio(period, region_id)
                metrics_data.append({
                    "region_id": region_id,
                    "period": period,
                    "metric_name": "保费预估差异率",
                    "metric_value": round(metric11, 2),
                    "applicable_business": "再保财险业务、再保人身险业务",
                    "metric_description": "业务年度预估分保费收入与实际分保费收入的差异占实际分保费收入的比率"
                })

        return pd.DataFrame(metrics_data)
